package ru.ifmo.math.matrix;

import java.util.*;

/**
 * @author avhaliullin
 */
public class Test {
    private static BinaryMatrix matrix1 = new ArrayMatrix(new byte[][]{
            {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
            {0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1},
            {0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1},
            {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}});
    private static BinaryMatrix matrix2 = new ArrayMatrix(new byte[][]{
            {1, 1, 0},
            {1, 1, 1}
    });

    private static BinaryMatrix matrix3 = new ArrayMatrix(new byte[][]{
            {0, 0, 1, 0, 1, 1},
            {1, 1, 1, 1, 1, 0},
            {1, 0, 1, 1, 0, 0}
    });

    private static BinaryMatrix matrix4 = new ArrayMatrix(new byte[][]{
            {1, 1, 1, 1, 1, 0},
            {0, 1, 0, 1, 1, 0},
            {0, 0, 1, 0, 1, 1}
    });

    private static BinaryMatrix matrix5 = new ArrayMatrix(new byte[][]{
            {1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1}
    });

    private static BinaryMatrix matrix6 = new ArrayMatrix(new byte[][]{
            {0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
            {1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1},
            {1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1},
            {0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0},
            {0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1},
            {0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0},
            {0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1},
            {1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1}
    });

    private static void fullCheck(BinaryMatrix matrix) {
        System.out.println(MatrixUtil.asString(MatrixUtil.systematize(matrix, new ArrayList<Transformation>())));

        BinaryMatrix checkoutMatrix = CodingUtil.checkoutMatrix(matrix);
        System.out.println(MatrixUtil.asString(checkoutMatrix));
        System.out.println(MatrixUtil.asString(MatrixUtil.multiply(matrix, MatrixUtil.transponate(checkoutMatrix))));
    }

    private static void fullCheck2(BinaryMatrix matrix) {
        System.out.println(MatrixUtil.asString(MatrixUtil.systematize2(matrix, new ArrayList<Transformation>())));

        BinaryMatrix originalMatrix = CodingUtil.originalMatrix(matrix);
        System.out.println(MatrixUtil.asString(originalMatrix));
        System.out.println(MatrixUtil.asString(MatrixUtil.multiply(originalMatrix, MatrixUtil.transponate(matrix))));

        List<byte[]> codes = CodingUtil.allCodes(originalMatrix);
        byte[] minWeightWord = CodingUtil.minWeightWord(codes);
        System.out.println("MWW: " + Arrays.toString(minWeightWord));
        System.out.println("d= " + CodingUtil.weight(minWeightWord));
        Map<Integer, Integer> spectrum = CodingUtil.spectrum(codes);
        for (Map.Entry<Integer, Integer> entry : spectrum.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }
        System.out.println();
        for (byte[] code : codes) {
            System.out.println(Arrays.toString(code));
        }
        System.out.println();
        List<byte[]> errors = CodingUtil.errors(codes);
        for (byte[] code : errors) {
            System.out.println(Arrays.toString(code));
        }
        System.out.println();

        Map<List<Byte>, byte[]> syndroms = CodingUtil.syndroms(errors, matrix);
        for (Map.Entry<List<Byte>, byte[]> entry : syndroms.entrySet()) {
            System.out.println(Arrays.toString(entry.getKey().toArray(new Byte[entry.getKey().size()])) + " => " + Arrays.toString(entry.getValue()));
        }

    }

    public static void main(String[] args) {
//        fullCheck2(matrix3);
//        fullCheck2(matrix6);
//        System.out.print(MatrixUtil.determinant(MatrixUtil.subMatrix(matrix6, 0, matrix6.getHeight(), 0, matrix6.getHeight())));
//        System.out.println("check 1");
//        fullCheck(new ArrayMatrix(new byte[][]{{1, 1, 0, 1, 0}, {0, 1, 1, 0, 1}}));
//        System.out.println("check 2");
        fullCheck(matrix5);
//        System.out.println(MatrixUtil.asString(matrix1));
//        System.out.println(MatrixUtil.asString(CodingUtil.checkoutMatrix(matrix1)));
//        System.out.println(MatrixUtil.asString(CodingUtil.checkoutMatrix(CodingUtil.checkoutMatrix(matrix1))));
    }
}
